﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using _10_HPBar.CharacterBase;
using _10_HPBar.GameFrame.Interface;
using _10_HPBar.GameFrame.System;
using _10_HPBar.Scene;
using _10_HPBar.Tool;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace _10_HPBar
{
    struct Pos
    {
        public int x;
        public int y;

        public Pos(int x = 0, int y = 0)
        {
            this.x = x;
            this.y = y;
        }
        public static bool operator ==(Pos left, Pos right)
        {
            return left.x == right.x && left.y == right.y;
        }
        public static bool operator !=(Pos left, Pos right)
        {
            return left.x != right.x || left.y != right.y;
        }
    }

    internal class Map
    {
        public enum Type
        {
            Empty = -1,
            Wall = 0,
            Spawn = 2,
            Box = 1,
            Enemy = 3,
            Player,
            Item,
            Upstairs = 99,
            Downstairs = 88
        }

        struct Data
        {
            public Pos pos;
            public Type type;
        }

        Dictionary<string, List<Data>> data;
        KeyValuePair<string, string>[] paths;
        string currentMapName;
        public int offsetX, offsetY;
        public int width, height;
        IScene scene;
        InfoSystem info;
        CombatSystem combat;

        public Map(KeyValuePair<string,string>[] paths, int width, int height, int offsetX, int offsetY, IScene scene, InfoSystem info, CombatSystem combat)
        {
            data = new();
            this.offsetX = offsetX;
            this.offsetY = offsetY;
            this.width = width;
            this.height = height;
            this.paths = paths;
            this.scene = scene;
            this.info = info;
            this.combat = combat;
            currentMapName = "";
            LoadData();
        }

        public void LoadData()
        {
            for (int i = 0; i < paths.Length; i++)
            {
                List<Data> dataList = new List<Data>();
                string temp = DataSystem.Instance.LoadData(paths[i].Value);

                string[] lines = temp.Split('\n');
                for (int j = 0; j < height; j++)
                {
                    string[] elements = lines[j].Split(',');
                    for (int k = 0; k < width; k++)
                    {
                        Data data = new Data();
                        data.pos.x = k;
                        data.pos.y = j;
                        data.type = (Type)int.Parse(elements[k]);
                        dataList.Add(data);
                    }
                }
                data[paths[i].Key] = dataList;
            }
        }

        public void Init()
        {
            if (!data.ContainsKey(currentMapName)) return;
            for (int i = 0; i < data[currentMapName].Count; i++)
            {
                switch (data[currentMapName][i].type)
                {
                    case Type.Spawn:
                        ((SceneMain)scene).player.SetPos(data[currentMapName][i].pos);
                        break;
                    case Type.Enemy:
                        ((SceneMain)scene).collision.RegisterObject(new Enemy($"怪物{i}", 20, 50, 10, 5, data[currentMapName][i].pos, this, "怪", info, (SceneMain)scene));
                        break;
                    case Type.Box:
                        ((SceneMain)scene).collision.RegisterObject(new Treasure(data[currentMapName][i].pos, offsetX, offsetY, "箱", i, 0));
                        break;
                }
            }
            InitPortal();
        }

        void InitPortal()
        {
            var str = DataSystem.Instance.LoadData("../../../Data/PortalData.json");
            JArray datas = JArray.Parse(str);
            foreach(var data in datas)
            {
                if (data["map"].ToString() == currentMapName)
                {
                    Portal.TargetData target = JsonConvert.DeserializeObject<Portal.TargetData>(data["TargetData"].ToString());
                    Portal portal = new Portal(int.Parse(data["x"].ToString()) + offsetX, int.Parse(data["y"].ToString()) + offsetY, target);
                    ((SceneMain)scene).collision.RegisterObject(portal);
                }
            }
        }

        public void End()
        {
            ((SceneMain)scene).collision.Clear();
        }

        public void Render()
        {
            string temp = string.Empty;
            for (int i = 0; i < data[currentMapName].Count; i++)
            {
                temp = string.Empty;
                switch (data[currentMapName][i].type)
                {
                    case Type.Wall:
                        temp = "■";
                        break;
                    case Type.Upstairs:
                        temp = "▲";
                        break;
                    case Type.Downstairs:
                        temp = "▼";
                        break;
                    case Type.Item:
                        temp = "★";
                        break;
                }
                if (temp == string.Empty)
                    continue;
                Utility.MyPrint(temp, data[currentMapName][i].pos.x + offsetX, data[currentMapName][i].pos.y + offsetY);
            }
        }

        public void ChangeMapByName(string name)
        {
            if (!data.ContainsKey(name)) return;
            End();
            currentMapName = name;
            Init();
            Console.Clear();
        }

        //public int ChangeNextMap(bool Up)
        //{
        //    int index = currentIndex;
        //    if (Up)
        //    {
        //        index++;
        //        if (index >= data.GetLength(0)-1)
        //            index = data.GetLength(0)-1;
        //    }
        //    else
        //    {
        //        index--;
        //        if (index < 0)
        //            index = 0;
        //    }
        //    ChangeMap(index);
        //    return index;
        //}

        public Type GetType(Pos pos)
        {
            int index = pos.y * width + pos.x;
            return data[currentMapName][index].type;
        }

        public void SetType(Pos pos, Type type)
        {
            int index = pos.y * width + pos.x;
            Data temp = data[currentMapName][index];
            temp.type = type;
            data[currentMapName][index] = temp;
        }
    }
}